package com.config;

import jakarta.servlet.Filter;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.*;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

import java.nio.charset.StandardCharsets;
import java.util.Collections;

import static org.springframework.boot.web.servlet.server.Session.SessionTrackingMode.COOKIE;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;


@Configuration
@PropertySource("classpath:application.properties")
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class})
public class WebServerConfig {


    @Bean
    public ServletWebServerFactory tomcatServletWebServerFactory(ServerProperties serverProperties) {
        TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
        serverFactory.setPort(serverProperties.getPort());

        Session session = new Session();

        session.setTrackingModes(
                // 如果不配置的话
                // 调用 jakarta.servlet.http.HttpServletResponse.encodeRedirectURL
//              如果请求含有 sessionId ,则会把 sessionId 拼接在 url 后面
//                例如 http://localhost/a/c;jsessionId=asdff?a=1&n=2
//                如果是浏览器重定向访问上面的地址,则会报 400 bad request 异常
                Collections.singleton(COOKIE)
        );

        serverFactory.setSession(session);
        return serverFactory;
    }


    @Bean
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties) {
        DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
//        配置servlet容器在启动时对 dispatcherServlet 进行初始化
        registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
        return registrationBean;
    }


    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public ViewResolver thymeleafViewResolver() {
        SpringTemplateEngine engine = new SpringTemplateEngine();

        engine.setTemplateResolver(templateResolver());

        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(engine);

        // 一定要求设置字符编码,否则乱码
        viewResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());

        return viewResolver;
    }

    @Bean
    public ClassLoaderTemplateResolver templateResolver() {
        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();

        templateResolver.setPrefix("/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }

    @Bean
    public CharacterEncodingFilter characterEncodingFilter() {
        return new CharacterEncodingFilter(StandardCharsets.UTF_8.name());
    }

    @Bean
   public FilterRegistrationBean<CharacterEncodingFilter> characterEncodingFilterRegistrationBean(){
        FilterRegistrationBean<CharacterEncodingFilter> registrationBean = new FilterRegistrationBean<>(characterEncodingFilter());

        registrationBean.addUrlPatterns("/*");
        registrationBean.setOrder(HIGHEST_PRECEDENCE);
        return registrationBean;


    }

}
